use std::{net::SocketAddr, sync::Arc};

use base_data::channel::{OriginateMsg, OriginateWay};
use bytes::Bytes;
use gw::{default_gateway, get_external_callout};
use tokio::net::UdpSocket;
use tools::{error::Error, global_defin::tokio_runtime::get_rt, ResultEx};
use tracing::{error, trace};

use crate::{empty_sockaddr, sip2::utils::get_str};

use super::register::reg_ser::load_user_transport;

pub(crate) mod gw;
pub(crate) mod udp;

#[derive(Debug)]
pub struct TransportLayerPacket {
	pub(crate) data: Bytes,
	// pub(crate) local_addr: SocketAddr,
	// pub(crate) remote_addr: SocketAddr,
	pub(crate) protocol: TransportProtocol,
}

impl Default for TransportLayerPacket {
	fn default() -> Self {
		Self {
			data: Default::default(),
			// local_addr: empty_sockaddr(),
			// remote_addr: "127.0.0.1:3456".parse().unwrap(),
			protocol: TransportProtocol::Unknown,
		}
	}
}

///给定协议层的接收处理方法
#[derive(Debug, Clone)]
pub enum TransportProtocol {
	Udp(Arc<UdpSocket>, SocketAddr),
	// TCP,
	// TLS,
	Unknown,
}

impl TransportProtocol {
	pub fn local_addr(&self) -> (&'static str, SocketAddr) {
		match self {
			//这个值必须有
			TransportProtocol::Udp(sock, _) => ("UDP", sock.local_addr().unwrap_or(empty_sockaddr())),
			// TransportProtocol::TCP => todo!(),
			// TransportProtocol::TLS => todo!(),
			TransportProtocol::Unknown => ("", empty_sockaddr()),
		}
	}
	pub fn set_peer_addr(mut self, addr: &SocketAddr) -> Self {
		match self {
			TransportProtocol::Udp(_, ref mut a) => *a = addr.clone(),
			// TransportProtocol::TCP => todo!(),
			// TransportProtocol::TLS => todo!(),
			TransportProtocol::Unknown => {}
		}

		self
	}

	pub fn send(&self, buf: Bytes) {
		match self {
			TransportProtocol::Udp(sock, addr) => {
				trace!("向{}发送数据:{}", addr, get_str(&buf));
				let sock = sock.clone();
				let addr = addr.clone();
				get_rt().spawn(async move {
					if let Err(e) = sock.send_to(&buf, &addr).await {
						error!("向远端发送信息失败:{e}");
					}
					trace!("发送完成!");
				});
			}
			// TransportProtocol::TCP => todo!(),
			// TransportProtocol::TLS => todo!(),
			TransportProtocol::Unknown => error!("协议未知,无法发送消息"),
		}
	}

	///向外呼出时,此方法负责找到发送数据的发送者和发送地址
	/// 直接向isp网关呼出时,是明确有本地呼叫对象和对端ip地址的.
	/// 从对外网关呼出时,只明确知道本地呼叫对象,而对外ip地址需要呼叫时指定
	/// 对用户呼叫时,也是明确有本地呼叫对象,而用户ip需要从注册信息中获取
	pub(crate) async fn from_call_way(way: &OriginateMsg) -> ResultEx<Self> {
		match &way.way {
			OriginateWay::IspGateway => Ok(default_gateway()),
			OriginateWay::ExternalGateway(peer_addr) => Ok(get_external_callout(&peer_addr)),
			OriginateWay::RegisterUser => load_user_transport(&way.called_num)
				.await
				.ok_or(Error::UserNotRegister),
			OriginateWay::UnKnown => Err(Error::LogicalError("不能通过未知的方式得到呼出地址")),
		}
	}

	pub(crate) fn peer_addr(&self) -> SocketAddr {
		match self {
			TransportProtocol::Udp(_, a) => *a,
			// TransportProtocol::TCP => todo!(),
			// TransportProtocol::TLS => todo!(),
			TransportProtocol::Unknown => empty_sockaddr(),
		}
	}
}
